#include "Sequence.h"
#include "StringUtility.h"
#include "LevelMap.h"
#include "MyGame.h"

Sequence::Sequence(string name)
{
    //ctor
    m_name = name;
    reset();
}

Sequence::~Sequence()
{
    //dtor
    m_steps.clear();

    m_waitingOn = NULL;
    m_level = NULL;
}

void Sequence::update()
{
    if (m_active) {
        Overlay *ovl = dynamic_cast<Overlay *>(m_waitingOn);
        StatefulUnit *stat = dynamic_cast<StatefulUnit *>(m_waitingOn);
        if (m_waitingOnCounter) {
               m_counter.update();
               // not ready to continue, bail out
               return;
        } else if (m_waitingOnUnit) {
            if (m_waitingOn == NULL) {
                m_waitingOnUnit = false;
            } else if (!(ovl == NULL) && ovl->hasFinished()) {
                m_waitingOnUnit = false;
                m_waitingOn = NULL;
            } else if (!(stat == NULL) && stat->hasFinished()) {
                m_waitingOnUnit = false;
                m_waitingOn = NULL;
            } else {
               // not ready to continue, bail out
                return;
            }
        }
        if (!(m_pendingAction.empty())) {
            // We have a pending action - this implies we processed a step which
            // said to wait first, we have finished waiting, time to execute
            // the index is already on the next step
            // So the next update will execute the next step
            performStep(m_pendingAction, false);
            m_pendingAction.clear();
            return;
        }

        // If we got here, it is either time to execute the next step,
        // or, if we are out of steps, to cease activity.
        if (m_index >= m_steps.size()) {
            // We have executed our last step
            reset();
            ((LevelMap *)m_level)->SequenceDone();
        } else {
            performStep(m_steps[m_index++], false);
        }
    }
}

void Sequence::performStep(string step, bool waitForCompletion)
{
    vector<string> split;
    string type;
    string cur;
    string val;

    tokenize(step, split, ",", 2);
    type = split[0];
    if (split.size()==2)
        cur = split[1];
    else
        cur.clear();

    if (type == "Wait") {
        // set the counter and we are done
        tokenize(cur, split, ",", 2);
        val = split[0];
        if (split.size()==2)
            cur = split[1];
        else
            cur.clear();
        m_counter.setMode(MILLI_SECONDS);
        m_counter.setLimit(atoi(val.c_str())*100);
        m_counter.start();
        if (!(cur.empty())) {m_pendingAction = cur;}
        return;
    } else if (type == "StartAfter") {
        tokenize(cur, split, ",", 2);
        val = split[0];
        if (split.size()==2)
            cur = split[1];
        else
            cur.clear();
        m_counter.setMode(MILLI_SECONDS);
        m_counter.setLimit(atoi(val.c_str())*100);
        m_counter.start();
        m_pendingAction = cur;
        return;
    } else if (type == "Start") {
        // loop back in
        if (!(cur.empty())) {performStep(cur, false);}
        return;
    } else if (type == "WaitForCompletion") {
        // loop back in
        if (!(cur.empty())) {performStep(cur, true);}
        return;
    } else if (type == "SetState") {
        LevelMap *lm = (LevelMap *)m_level;
        tokenize(cur, split, ",", 3);
        if (waitForCompletion) m_waitingOnUnit = lm->SetState(split[0], split[1]);
        else lm->SetState(split[0], split[1]);
        if (split.size()>2) {m_pendingAction = split[2];}
        return;
    } else if (type == "FailIf") {
        tokenize(cur, split, ",", 2);
        MyGame* game = MyGame::GetMyGame();
        if (game->GetGameState()->GetCurrentState(game->GetCurrentLevelMapName(), split[0]) == split[1]) {
            reset();
            ((LevelMap *)m_level)->SequenceDone();
            return;
        }
    } else if (type == "RestoreState") {
        MyGame* game = MyGame::GetMyGame();
        string temp = game->GetGameState()->GetCurrentState(game->GetCurrentLevelMapName(),cur);
        if (! temp.empty()) {
            LevelMap *lm = (LevelMap *)m_level;
            lm->SetState(cur, temp);
        }
    } else if (type == "MarkLevel") {
        tokenize(cur, split, ",", 2);
        MyGame* game = MyGame::GetMyGame();
        game->GetGameState()->SetCurrentState(game->GetCurrentLevelMapName(),split[0],split[1]);
    } else if (type == "Done") {
        reset();
        ((LevelMap *)m_level)->SequenceDone();
        return;
    }
};
